package work.mediway.mdm.biz.service.patient.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mediway.hos.common.utils.ExceptionUtil;
import com.mediway.hos.common.utils.spring.SpringUtils;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.handler.BeanListHandler;
import cn.hutool.db.sql.SqlExecutor;
import cn.hutool.extra.spring.SpringUtil;
import work.mediway.mdm.core.helper.BaseDatabaseHelper;
import work.mediway.mdm.core.thread.DimplesTaskExecutor;
import work.mediway.mdm.biz.service.patient.PaAddressService;
import work.mediway.mdm.biz.vo.patient.StatisticsPatientNumVO;
import work.mediway.mdm.core.exception.BizException;
import work.mediway.mdm.core.properties.MdmProperties;
import work.mediway.mdm.biz.entity.patient.PaAddress;
import work.mediway.mdm.biz.mapper.patient.PaAddressMapper;

/**
 * @author zhongyj <1126834403@qq.com><br/>
 * @date 2020/12/10
 */
@Transactional(rollbackFor = Exception.class)
@Service
public class PaAddressServiceImpl extends ServiceImpl<PaAddressMapper, PaAddress> implements PaAddressService {

    @Autowired
    private MdmProperties properties;

    @Override
    public Map<String, List<Map<String, Object>>> statisticsNumByArea(String addressTypeCode) {
        if (StrUtil.isBlank(addressTypeCode)) {
            addressTypeCode = properties.getDefAddressTypeCode();
        }
        final String typeCode = addressTypeCode;
        // 返回最终结果
        Map<String, List<Map<String, Object>>> result = MapUtil.newHashMap();
        // 整合的省份结果
        List<Map<String, Object>> provResultList = CollUtil.newArrayList();
        // 整合的城市结果
        List<Map<String, Object>> cityResultList = CollUtil.newArrayList();
        // 存储任务
        List<Callable<List<StatisticsPatientNumVO>>> task = CollUtil.newArrayList();
        // --------------------------------------------- 按省份统计任务 ------------------------------------------- //
        task.add(() -> {
            PaAddressMapper paAddressMapper = SpringUtil.getBean(PaAddressMapper.class);
            return paAddressMapper.statisticsProvNumByAreaProv(typeCode);
        });
        task.add(() -> {
            PaAddressMapper paAddressMapper = SpringUtil.getBean(PaAddressMapper.class);
            return paAddressMapper.statisticsProvNumByAreaCity(typeCode);
        });
        task.add(() -> {
            PaAddressMapper paAddressMapper = SpringUtil.getBean(PaAddressMapper.class);
            return paAddressMapper.statisticsProvNumByAreaCountry(typeCode);
        });
        // --------------------------------------------- 按城市统计任务 ------------------------------------------- //
        task.add(() -> {
            PaAddressMapper paAddressMapper = SpringUtil.getBean(PaAddressMapper.class);
            return paAddressMapper.statisticsCityNumByAreaCity(typeCode);
        });
        task.add(() -> {
            PaAddressMapper paAddressMapper = SpringUtil.getBean(PaAddressMapper.class);
            return paAddressMapper.statisticsCityNumByAreaCounty(typeCode);
        });
        // 提交任务
        DimplesTaskExecutor<List<StatisticsPatientNumVO>> executor = new DimplesTaskExecutor<>("StatisticsPatientArea");
        ExecutorCompletionService<List<StatisticsPatientNumVO>> completionService = executor.getCompletionService();
        for (Callable<List<StatisticsPatientNumVO>> listCallable : task) {
            completionService.submit(listCallable);
        }
        //获取和整合结果
        Map<String, Integer> taskProvMap = MapUtil.newHashMap();
        Map<String, Integer> taskCityMap = MapUtil.newHashMap();
        for (int i = 0, len = task.size(); i < len; i++) {
            try {
                List<StatisticsPatientNumVO> provList = completionService.take().get();
                if (CollUtil.isEmpty(provList)) {
                    continue;
                }
                for (StatisticsPatientNumVO vo : provList) {
                    // 表示是统计的省份数据
                    if (StrUtil.isNotBlank(vo.getProvinceDesc())) {
                        Integer num = taskProvMap.get(vo.getProvinceDesc());
                        taskProvMap.put(vo.getProvinceDesc(), num == null ? vo.getPatientNum() : num + vo.getPatientNum());
                    } else if (StrUtil.isNotBlank(vo.getCityDesc())) {
                        // 表示是城市的省份数据
                        Integer num = taskCityMap.get(vo.getCityDesc());
                        taskCityMap.put(vo.getCityDesc(), num == null ? vo.getPatientNum() : num + vo.getPatientNum());
                    }
                }
            } catch (InterruptedException | ExecutionException e) {
                throw new BizException("统计患者地区分布", e);
            }
        }
        List<String> provDesc = null;
        List<String> cityDesc = null;
        try {
            provDesc = SqlExecutor.query(SpringUtils.getBean(BaseDatabaseHelper.class).getLocalConnection(), "SELECT PROV_Desc FROM mdm_User.HOS_Province", new BeanListHandler<>(String.class));
            cityDesc = SqlExecutor.query(SpringUtils.getBean(BaseDatabaseHelper.class).getLocalConnection(), "SELECT CITY_Desc FROM mdm_User.HOS_City", new BeanListHandler<>(String.class));
        } catch (Exception e) {
            e.printStackTrace();
            log.error(ExceptionUtil.getExceptionMessage(e));
        }
        assert provDesc != null;
        for (String s : provDesc) {
            Map<String, Object> map = MapUtil.newHashMap(1);
            map.put("provDesc", s);
            map.put("patientNum", taskProvMap.get(s) == null ? 0 : taskProvMap.get(s));
            provResultList.add(map);
        }
        assert cityDesc != null;
        for (String s : cityDesc) {
            Map<String, Object> map = MapUtil.newHashMap(1);
            map.put("cityDesc", s);
            map.put("patientNum", taskCityMap.get(s) == null ? 0 : taskCityMap.get(s));
            cityResultList.add(map);
        }
        result.put("prov", provResultList);
        result.put("city", cityResultList);
        return result;
    }
}
